/*
 * Copyright (C) 2011-2013 Eric Lasota
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */
#include "rdx_intrinsics.hpp"
#include "rdx_programmability.hpp"
#include "rdx_lut.hpp"
#include "rdx_marshal.hpp"
#include "rdx_runtime.hpp"
#include "rdx_objectmanagement.hpp"
#include "rdx_blockcopy.hpp"

#define NTHROW_EXCEPTION(lbl, name)	\
	do\
	{\
		RDX_NTRY(lbl, ctx)\
		{\
			CRef<const String> nthrow_exception_str;\
			RDX_PROTECT_ASSIGN(ctx, nthrow_exception_str, objm->CreateStringASCII(ctx, name, -1, true));\
			thread->ex = objm->LookupSymbolSimple(ctx, nthrow_exception_str).Cast<Exception>();\
			return RuntimeState::Exception;\
		}\
		RDX_NCATCH(lbl, ctx)\
		{\
			RDX_RETHROWV(ctx, RuntimeState::Exception);\
		}\
		RDX_NENDTRY(lbl)\
	} while(0)

#define THROW_EXCEPTION(name)	NTHROW_EXCEPTION(EH, name)

#define ARITHMETIC_OP(name, type, op)	\
	static int RDX_DECL_API name (OperationContext *ctx, IObjectManager *objm, const Method *m, RuntimeThread *thread, RuntimeStackValue *prv)\
	{\
		struct parameterTypes\
		{\
			Value<type> v;\
			Value<type> self;\
		};\
		parameterTypes *params = ParametersFromPRV<parameterTypes>(prv);\
		ReturnValuesFromPRV<Value<type> >(prv)->GetValue() = (params->self.GetValue()) op (params->v.GetValue());\
		return RuntimeState::Active;\
	}

#define ARITHMETIC_OP_UNARY(name, type, op)	\
	static int RDX_DECL_API name (OperationContext *ctx, IObjectManager *objm, const Method *m, RuntimeThread *thread, RuntimeStackValue *prv)\
	{\
		struct parameterTypes\
		{\
			Value<type> self;\
		};\
		parameterTypes *params = ParametersFromPRV<parameterTypes>(prv);\
		ReturnValuesFromPRV<Value<type> >(prv)->GetValue() = op (params->self.GetValue());\
		return RuntimeState::Active;\
	}

#define CAST_FUNC(name, type, to)	\
	static int RDX_DECL_API name (OperationContext *ctx, IObjectManager *objm, const Method *m, RuntimeThread *thread, RuntimeStackValue *prv)\
	{\
		struct parameterTypes\
		{\
			Value<type> self;\
		};\
		parameterTypes *params = ParametersFromPRV<parameterTypes>(prv);\
		ReturnValuesFromPRV<Value<to> >(prv)->GetValue() = static_cast<to>(params->self.GetValue());\
		return RuntimeState::Active;\
	}


#define ARITHMETIC_OP_ZERO_CHECKED(name, type, op)	\
	static int RDX_DECL_API name (OperationContext *ctx, IObjectManager *objm, const Method *m, RuntimeThread *thread, RuntimeStackValue *prv)\
	{\
		struct parameterTypes\
		{\
			Value<type> v;\
			Value<type> self;\
		};\
		parameterTypes *params = ParametersFromPRV<parameterTypes>(prv);\
		if(!(params->v.GetValue()))\
			THROW_EXCEPTION("Core.RDX.DivideByZeroException.instance");\
		ReturnValuesFromPRV<Value<type> >(prv)->GetValue() = (params->self.GetValue()) op (params->v.GetValue());\
		return RuntimeState::Active;\
	}

#define ARITHMETIC_COMPARE(name, type, op)	\
	static int RDX_DECL_API name (OperationContext *ctx, IObjectManager *objm, const Method *m, RuntimeThread *thread, RuntimeStackValue *prv)\
	{\
		struct parameterTypes\
		{\
			Value<type> v;\
			Value<type> self;\
		};\
		parameterTypes *params = ParametersFromPRV<parameterTypes>(prv);\
		ReturnValuesFromPRV<Value<Bool> >(prv)->GetValue() = ((params->self.GetValue()) op (params->v.GetValue())) ? TrueValue : FalseValue;\
		return RuntimeState::Active;\
	}


namespace RDX
{
	namespace Builtins
	{
		using namespace RDX::Marshaling;
		using namespace RDX::ObjectManagement;
		using namespace RDX::Programmability;
		using namespace RDX::Utility;

		typedef StaticLookupTable<StaticLookupStringKey<Char, char>, Programmability::NativeCallback> BuiltinLUT;

		ARITHMETIC_OP(intAdd, Int, +)
		ARITHMETIC_OP(intSub, Int, -)
		ARITHMETIC_OP(intMul, Int, *)
		ARITHMETIC_OP_ZERO_CHECKED(intDiv, Int, /)
		ARITHMETIC_OP_ZERO_CHECKED(intMod, Int, %)
		ARITHMETIC_OP_UNARY(intNeg, Int, -)
		
		CAST_FUNC(largeIntToInt, LargeInt, Int)
		CAST_FUNC(intToLargeInt, Int, LargeInt)
		CAST_FUNC(intToLong, Int, Long)
		CAST_FUNC(intToShort, Int, Short)
		CAST_FUNC(intToDouble, Int, Double)
		CAST_FUNC(intToFloat, Int, Float)

		ARITHMETIC_COMPARE(intLT, Int, <)
		ARITHMETIC_COMPARE(intGT, Int, >)
		ARITHMETIC_COMPARE(intLE, Int, <=)
		ARITHMETIC_COMPARE(intGE, Int, >=)
		ARITHMETIC_COMPARE(intEQ, Int, ==)
		ARITHMETIC_COMPARE(intNE, Int, !=)
		
		ARITHMETIC_OP(largeIntAdd, LargeInt, +)
		ARITHMETIC_OP(largeIntSub, LargeInt, -)
		ARITHMETIC_OP(largeIntMul, LargeInt, *)
		ARITHMETIC_OP_ZERO_CHECKED(largeIntDiv, LargeInt, /)
		ARITHMETIC_OP_ZERO_CHECKED(largeIntMod, LargeInt, %)
		ARITHMETIC_OP_UNARY(largeIntNeg, LargeInt, -)

		ARITHMETIC_COMPARE(largeIntLT, LargeInt, <)
		ARITHMETIC_COMPARE(largeIntGT, LargeInt, >)
		ARITHMETIC_COMPARE(largeIntLE, LargeInt, <=)
		ARITHMETIC_COMPARE(largeIntGE, LargeInt, >=)
		ARITHMETIC_COMPARE(largeIntEQ, LargeInt, ==)
		ARITHMETIC_COMPARE(largeIntNE, LargeInt, !=)

		ARITHMETIC_OP(floatAdd, Float, +)
		ARITHMETIC_OP(floatSub, Float, -)
		ARITHMETIC_OP(floatMul, Float, *)
		ARITHMETIC_OP(floatDiv, Float, /)
		ARITHMETIC_OP_UNARY(floatNeg, Float, -)
		
		ARITHMETIC_COMPARE(floatLT, Float, <)
		ARITHMETIC_COMPARE(floatGT, Float, >)
		ARITHMETIC_COMPARE(floatLE, Float, <=)
		ARITHMETIC_COMPARE(floatGE, Float, >=)
		ARITHMETIC_COMPARE(floatEQ, Float, ==)
		ARITHMETIC_COMPARE(floatNE, Float, !=)
		
		ARITHMETIC_OP(doubleAdd, Double, +)
		ARITHMETIC_OP(doubleSub, Double, -)
		ARITHMETIC_OP(doubleMul, Double, *)
		ARITHMETIC_OP(doubleDiv, Double, /)
		ARITHMETIC_OP_UNARY(doubleNeg, Double, -)
		
		ARITHMETIC_COMPARE(doubleLT, Double, <)
		ARITHMETIC_COMPARE(doubleGT, Double, >)
		ARITHMETIC_COMPARE(doubleLE, Double, <=)
		ARITHMETIC_COMPARE(doubleGE, Double, >=)
		ARITHMETIC_COMPARE(doubleEQ, Double, ==)
		ARITHMETIC_COMPARE(doubleNE, Double, !=)

		template<class _T>
		static int RDX_DECL_API signedIntToStringOp(OperationContext *ctx, IObjectManager *objm, const Method *m, RuntimeThread *thread, RuntimeStackValue *prv)
		{
			Char digitStack[sizeof(_T)*3+1];
			Char result[sizeof(_T)*3+1];
			LargeInt digits = 0;
			LargeInt chars = 0;
			bool negative = false;
			Char *out = result;
			
			_T v = (ParametersFromPRV<Value<_T> >(prv))->GetValue();

			if(v < 0)
			{
				*out++ = static_cast<Char>('-');
				chars++;
				negative = true;
			}

			do
			{
				if(negative)
					digitStack[digits++] = static_cast<Char>(-(v % _T(10)) + '0');
				else
					digitStack[digits++] = static_cast<Char>((v % _T(10)) + '0');
				v = v / _T(10);
			} while(v);

			while(digits)
			{
				*out++ = digitStack[--digits];
				chars++;
			}

			const String *str = NULL;
			RDX_TRY(ctx)
			{
				RDX_PROTECT_ASSIGN(ctx, str, objm->CreateString(ctx, result, chars));
				ReturnValuesFromPRV<Value<const String *> >(prv)->GetValue() = str;
			}
			RDX_CATCH(ctx)
			{
				ReturnValuesFromPRV<Value<const String *> >(prv)->GetValue() = NULL;
				NTHROW_EXCEPTION(EH2, "Core.RDX.InternalFailureException.instance");
			}
			RDX_ENDTRY

			return RuntimeState::Active;
		}
		
		//Core.hashcode/methods/ToInt()
		static int RDX_DECL_API hashCodeToInt(OperationContext *ctx, IObjectManager *objm, const Method *m, RuntimeThread *thread, RuntimeStackValue *prv)
		{
			struct myParameters
			{
				Value<HashValue> hash;
			};

			struct myReturnValues
			{
				Value<Int> i;
			};

			myParameters *params = ParametersFromPRV<myParameters>(prv);
			myReturnValues *rv = ReturnValuesFromPRV<myReturnValues>(prv);

			rv->i.GetValue() = static_cast<Int>(params->hash.GetValue());

			return RuntimeState::Active;
		}

		//Core.hashcode/methods/From(const Core.varying)
		static int RDX_DECL_API hashVarying(OperationContext *ctx, IObjectManager *objm, const Method *m, RuntimeThread *thread, RuntimeStackValue *prv)
		{
			RDX_TRY(ctx)
			{
				struct myParameters
				{
					Value<TypedRuntimePointer> key;
				};

				struct myReturnValues
				{
					Value<HashValue> hv;
				};

				myParameters *params = ParametersFromPRV<myParameters>(prv);
				myReturnValues *rv = ReturnValuesFromPRV<myReturnValues>(prv);

				rv->hv.GetValue() = 0;

				LargeInt keySize, align;
				RDX_PROTECT(ctx, objm->TypeValueSize(ctx, params->key.GetValue().type, keySize, align));

				rv->hv.GetValue() = HashBytes(params->key.GetValue().rtp.valueRef, static_cast<size_t>(keySize));

				return RuntimeState::Active;
			}
			RDX_CATCH(ctx)
			{
				thread->ex = static_cast<Exception*>(objm->GetBuiltIns()->providerDictionary[X_InvalidOperationException]);
				return RuntimeState::Exception;
			}
			RDX_ENDTRY
		}

		static int RDX_DECL_API getCurrentThread(OperationContext *ctx, IObjectManager *objm, const Method *m, RuntimeThread *thread, RuntimeStackValue *prv)
		{
			struct returnTypes
			{
				Value<RuntimeThread*> t;
			};
			returnTypes *rv = ReturnValuesFromPRV<returnTypes>(prv);

			rv->t.GetValue() = thread;
			return RuntimeState::Active;
		}
		
		static int RDX_DECL_API objectGetType(OperationContext *ctx, IObjectManager *objm, const Method *m, RuntimeThread *thread, RuntimeStackValue *prv)
		{
			struct parameterTypes
			{
				Value<void*> self;
			};
			parameterTypes *params = ParametersFromPRV<parameterTypes>(prv);
			ReturnValuesFromPRV<Value<const Type *> >(prv)->GetValue() = GCInfo::From(params->self.GetValue())->containerType;
			return RuntimeState::Active;
		}

		static int RDX_DECL_API objectCanConvertTo(OperationContext *ctx, IObjectManager *objm, const Method *m, RuntimeThread *thread, RuntimeStackValue *prv)
		{
			struct parameterTypes
			{
				Value<const Type*> targetType;
				Value<void*> self;
			};
			parameterTypes *params = ParametersFromPRV<parameterTypes>(prv);
			ReturnValuesFromPRV<Value<Bool> >(prv)->GetValue() = (objm->ObjectCompatible(params->self.GetValue(), params->targetType.GetValue())) ? TrueValue : FalseValue;
			return RuntimeState::Active;
		}

		static int RDX_DECL_API objectGetGlobalSymbol(OperationContext *ctx, IObjectManager *objm, const Method *m, RuntimeThread *thread, RuntimeStackValue *prv)
		{
			struct parameterTypes
			{
				Value<void*> self;
			};
			parameterTypes *params = ParametersFromPRV<parameterTypes>(prv);
			ReturnValuesFromPRV<Value<const String *> >(prv)->GetValue() = GCInfo::From(params->self.GetValue())->gstSymbol;
			return RuntimeState::Active;
		}

		static int RDX_DECL_API stringChars(OperationContext *ctx, IObjectManager *objm, const Method *m, RuntimeThread *thread, RuntimeStackValue *prv)
		{
			struct parameterTypes
			{
				Value<const String*> self;
			};
			struct returnValueTypes
			{
				Value<const Char*> chars;
			};
			parameterTypes *params = ParametersFromPRV<parameterTypes>(prv);
			returnValueTypes *returnValues = ReturnValuesFromPRV<returnValueTypes>(prv);

			returnValues->chars.GetValue() = params->self.GetValue()->AsChars();

			return RuntimeState::Active;
		}

		static int RDX_DECL_API stringLength(OperationContext *ctx, IObjectManager *objm, const Method *m, RuntimeThread *thread, RuntimeStackValue *prv)
		{
			struct parameterTypes
			{
				Value<const String*> self;
			};
			struct returnValueTypes
			{
				Value<Int> length;
			};
			parameterTypes *params = ParametersFromPRV<parameterTypes>(prv);
			returnValueTypes *returnValues = ReturnValuesFromPRV<returnValueTypes>(prv);

			returnValues->length.GetValue() = static_cast<Int>(params->self.GetValue()->Length());

			return RuntimeState::Active;
		}

		static int RDX_DECL_API stringConcat(OperationContext *ctx, IObjectManager *objm, const Method *m, RuntimeThread *thread, RuntimeStackValue *prv)
		{
			struct parameterTypes
			{
				Value<const String*> rs;
				Value<const String*> self;
			};
			struct returnValueTypes
			{
				Value<const String*> concatenated;
			};
			parameterTypes *params = ParametersFromPRV<parameterTypes>(prv);
			returnValueTypes *returnValues = ReturnValuesFromPRV<returnValueTypes>(prv);

			RDX_TRY(ctx)
			{
				RDX_PROTECT_ASSIGN(ctx, returnValues->concatenated.GetValue(), objm->CreateStringConcatenated(ctx, params->self.GetValue(), params->rs.GetValue()));
			}
			RDX_CATCH(ctx)
			{
				RDX_RETHROWV(ctx, RuntimeState::Exception);
			}
			RDX_ENDTRY

			return RuntimeState::Active;
		}

		static int RDX_DECL_API stringSubstring(OperationContext *ctx, IObjectManager *objm, const Method *m, RuntimeThread *thread, RuntimeStackValue *prv)
		{
			struct parameterTypes
			{
				Value<Int> offset;
				Value<const String*> self;
			};
			struct returnValueTypes
			{
				Value<const String*> str;
			};
			parameterTypes *params = ParametersFromPRV<parameterTypes>(prv);
			returnValueTypes *returnValues = ReturnValuesFromPRV<returnValueTypes>(prv);

			LargeInt offset = params->offset.GetValue();
			const LargeInt nChars = params->self.GetValue()->Length();

			if(offset < 0)
				offset = 0;

			if(offset > nChars)
				offset = nChars;

			const LargeInt length = nChars - offset;

			if(offset == 0)
			{
				returnValues->str.GetValue() = params->self.GetValue();
				return RuntimeState::Active;
			}

			RDX_TRY(ctx)
			{
				RDX_PROTECT_ASSIGN(ctx, returnValues->str.GetValue(), objm->CreateString(ctx, params->self.GetValue()->AsChars() + offset, length));
			}
			RDX_CATCH(ctx)
			{
				RDX_RETHROWV(ctx, RuntimeState::Exception);
			}
			RDX_ENDTRY

			return RuntimeState::Active;
		}

		static int RDX_DECL_API stringSubstringWithLength(OperationContext *ctx, IObjectManager *objm, const Method *m, RuntimeThread *thread, RuntimeStackValue *prv)
		{
			struct parameterTypes
			{
				Value<Int> length;
				Value<Int> offset;
				Value<const String*> self;
			};
			struct returnValueTypes
			{
				Value<const String*> str;
			};
			parameterTypes *params = ParametersFromPRV<parameterTypes>(prv);
			returnValueTypes *returnValues = ReturnValuesFromPRV<returnValueTypes>(prv);

			LargeInt length = params->length.GetValue();
			LargeInt offset = params->offset.GetValue();
			const LargeInt nChars = params->self.GetValue()->Length();

			if(offset < 0)
			{
				length += offset;
				offset = 0;
			}

			if(offset > nChars)
				offset = nChars;

			if(length < 0)
				length = 0;
			else if(length > nChars - offset)
				length = nChars - offset;

			if(offset == 0 && length == nChars)
			{
				returnValues->str.GetValue() = params->self.GetValue();
				return RuntimeState::Active;
			}

			RDX_TRY(ctx)
			{
				RDX_PROTECT_ASSIGN(ctx, returnValues->str.GetValue(), objm->CreateString(ctx, params->self.GetValue()->AsChars() + offset, length));
			}
			RDX_CATCH(ctx)
			{
				RDX_RETHROWV(ctx, RuntimeState::Exception);
			}
			RDX_ENDTRY

			return RuntimeState::Active;
		}

		static int RDX_DECL_API stringFromChars(OperationContext *ctx, IObjectManager *objm, const Method *m, RuntimeThread *thread, RuntimeStackValue *prv)
		{
			struct parameterTypes
			{
				Value<Int> length;
				Value<Int> offset;
				Value<const Char*> chars;
			};
			struct returnValueTypes
			{
				Value<const String*> str;
			};
			parameterTypes *params = ParametersFromPRV<parameterTypes>(prv);
			returnValueTypes *returnValues = ReturnValuesFromPRV<returnValueTypes>(prv);

			LargeInt length = params->length.GetValue();
			LargeInt offset = params->offset.GetValue();
			const LargeInt nChars = GCInfo::From(params->chars.GetValue())->numElements;

			if(offset < 0)
			{
				length += offset;
				offset = 0;
			}

			if(offset > nChars)
				offset = nChars;

			if(length < 0)
				length = 0;
			else if(length > nChars - offset)
				length = nChars - offset;

			RDX_TRY(ctx)
			{
				RDX_PROTECT_ASSIGN(ctx, returnValues->str.GetValue(), objm->CreateString(ctx, params->chars.GetValue() + offset, length));
			}
			RDX_CATCH(ctx)
			{
				RDX_RETHROWV(ctx, RuntimeState::Exception);
			}
			RDX_ENDTRY

			return RuntimeState::Active;
		}

		static int RDX_DECL_API stringIndex(OperationContext *ctx, IObjectManager *objm, const Method *m, RuntimeThread *thread, RuntimeStackValue *prv)
		{
			struct parameterTypes
			{
				Value<Int> index;
				Value<const String*> self;
			};
			struct returnValueTypes
			{
				Value<Char> ch;
			};
			parameterTypes *params = ParametersFromPRV<parameterTypes>(prv);
			returnValueTypes *returnValues = ReturnValuesFromPRV<returnValueTypes>(prv);

			const String *str = params->self.GetValue();
			const LargeInt nChars = str->Length();
			const LargeInt offset = params->index.GetValue();

			if(offset < 0 || offset >= nChars)
				THROW_EXCEPTION("Core.RDX.IndexOutOfBoundsException.instance");

			returnValues->ch.GetValue() = str->AsChars()[offset];
			return RuntimeState::Active;
		}

		static int RDX_DECL_API charToString(OperationContext *ctx, IObjectManager *objm, const Method *m, RuntimeThread *thread, RuntimeStackValue *prv)
		{
			struct parameterTypes
			{
				Value<Char> self;
			};
			struct returnValueTypes
			{
				Value<const String*> str;
			};
			parameterTypes *params = ParametersFromPRV<parameterTypes>(prv);
			returnValueTypes *returnValues = ReturnValuesFromPRV<returnValueTypes>(prv);

			RDX_TRY(ctx)
			{
				RDX_PROTECT_ASSIGN(ctx, returnValues->str.GetValue(), objm->CreateString(ctx, &params->self.GetValue(), 1));
			}
			RDX_CATCH(ctx)
			{
				RDX_RETHROWV(ctx, RuntimeState::Exception);
			}
			RDX_ENDTRY

			return RuntimeState::Active;
		}

		static int RDX_DECL_API boolToString(OperationContext *ctx, IObjectManager *objm, const Method *m, RuntimeThread *thread, RuntimeStackValue *prv)
		{
			struct parameterTypes
			{
				Value<Bool> self;
			};
			struct returnValueTypes
			{
				Value<const String*> str;
			};
			parameterTypes *params = ParametersFromPRV<parameterTypes>(prv);
			returnValueTypes *returnValues = ReturnValuesFromPRV<returnValueTypes>(prv);

			RDX_TRY(ctx)
			{
				const Char *pv = (params->self.GetValue() == FalseValue) ? RDX_STATIC_STRING("false") : RDX_STATIC_STRING("true");
				RDX_PROTECT_ASSIGN(ctx, returnValues->str.GetValue(), objm->CreateString(ctx, pv));
			}
			RDX_CATCH(ctx)
			{
				RDX_RETHROWV(ctx, RuntimeState::Exception);
			}
			RDX_ENDTRY

			return RuntimeState::Active;
		}

		static BuiltinLUT::Entry bi_builtins[] =
		{
			{ "Core.largeint/methods/#coerce(Core.int)",	largeIntToInt },

			{ "Core.largeint/methods/__add(Core.largeint)",	largeIntAdd },
			{ "Core.largeint/methods/__sub(Core.largeint)",	largeIntSub },
			{ "Core.largeint/methods/__mul(Core.largeint)",	largeIntMul },
			{ "Core.largeint/methods/__div(Core.largeint)",	largeIntDiv },
			{ "Core.largeint/methods/__mod(Core.largeint)",	largeIntMod },
			{ "Core.largeint/methods/__neg()",				largeIntNeg },
			{ "Core.largeint/methods/#coerce(Core.string)",	signedIntToStringOp<LargeInt> },
			{ "Core.largeint/methods/__lt(Core.largeint)",	largeIntLT },
			{ "Core.largeint/methods/__gt(Core.largeint)",	largeIntGT },
			{ "Core.largeint/methods/__le(Core.largeint)",	largeIntLE },
			{ "Core.largeint/methods/__ge(Core.largeint)",	largeIntGE },
			{ "Core.largeint/methods/__eq(Core.largeint)",	largeIntEQ },
			{ "Core.largeint/methods/__ne(Core.largeint)",	largeIntNE },


			{ "Core.int/methods/__add(Core.int)",			intAdd },
			{ "Core.int/methods/__sub(Core.int)",			intSub },
			{ "Core.int/methods/__mul(Core.int)",			intMul },
			{ "Core.int/methods/__div(Core.int)",			intDiv },
			{ "Core.int/methods/__mod(Core.int)",			intMod },
			{ "Core.int/methods/__neg()",					intNeg },
			{ "Core.int/methods/#coerce(Core.largeint)",	intToLargeInt },
			{ "Core.int/methods/#coerce(Core.long)",		intToLong },
			{ "Core.int/methods/#coerce(Core.short)",		intToShort },
			{ "Core.int/methods/#coerce(Core.double)",		intToDouble },
			{ "Core.int/methods/#coerce(Core.float)",		intToFloat },
			{ "Core.int/methods/#coerce(Core.string)",		signedIntToStringOp<Int> },
			{ "Core.int/methods/__lt(Core.int)",			intLT },
			{ "Core.int/methods/__gt(Core.int)",			intGT },
			{ "Core.int/methods/__le(Core.int)",			intLE },
			{ "Core.int/methods/__ge(Core.int)",			intGE },
			{ "Core.int/methods/__eq(Core.int)",			intEQ },
			{ "Core.int/methods/__ne(Core.int)",			intNE },

			{ "Core.float/methods/__add(Core.float)",		floatAdd },
			{ "Core.float/methods/__sub(Core.float)",		floatSub },
			{ "Core.float/methods/__mul(Core.float)",		floatMul },
			{ "Core.float/methods/__div(Core.float)",		floatDiv },
			{ "Core.float/methods/__neg()",					floatNeg },
			{ "Core.float/methods/__lt(Core.float)",		floatLT },
			{ "Core.float/methods/__gt(Core.float)",		floatGT },
			{ "Core.float/methods/__le(Core.float)",		floatLE },
			{ "Core.float/methods/__ge(Core.float)",		floatGE },
			{ "Core.float/methods/__eq(Core.float)",		floatEQ },
			{ "Core.float/methods/__ne(Core.float)",		floatNE },

			{ "Core.double/methods/__add(Core.double)",		doubleAdd },
			{ "Core.double/methods/__sub(Core.double)",		doubleSub },
			{ "Core.double/methods/__mul(Core.double)",		doubleMul },
			{ "Core.double/methods/__div(Core.double)",		doubleDiv },
			{ "Core.double/methods/__neg()",				doubleNeg },
			{ "Core.double/methods/__lt(Core.double)",		doubleLT },
			{ "Core.double/methods/__gt(Core.double)",		doubleGT },
			{ "Core.double/methods/__le(Core.double)",		doubleLE },
			{ "Core.double/methods/__ge(Core.double)",		doubleGE },
			{ "Core.double/methods/__eq(Core.double)",		doubleEQ },
			{ "Core.double/methods/__ne(Core.double)",		doubleNE },

			{ "Core.Object/methods/GetType()",				objectGetType },
			{ "Core.Object/methods/CanConvertTo(notnull Core.RDX.Type)",
															objectCanConvertTo },
			{ "Core.Object/methods/GlobalSymbol()",			objectGetGlobalSymbol },

			{ "Core.string/methods/Chars()",				stringChars },
			{ "Core.string/methods/Length()",				stringLength },
			{ "Core.string/methods/__add(Core.string)",		stringConcat },
			{ "Core.string/methods/Substring(Core.int)",	stringSubstring },
			{ "Core.string/methods/Substring(Core.int,Core.int)",stringSubstringWithLength },
			{ "Core.string/methods/__index(Core.int)",		stringIndex },
			{ "Core.string/methods/FromChars(notnull #Core.char[C],Core.int,Core.int)",	stringFromChars },
			{ "Core.char/methods/#coerce(Core.string)",		charToString },

			{ "Core.bool/methods/#coerce(Core.string)",		boolToString },

			{ "Core.RDX.Thread/methods/GetCurrent()",		getCurrentThread },

			{ "Core.hashcode/methods/ToInt()",					hashCodeToInt },
			{ "Core.hashcode/methods/From(const Core.varying)", hashVarying },

		};
		BuiltinLUT bi_lut(bi_builtins, sizeof(bi_builtins)/sizeof(bi_builtins[0]));
	}

	namespace Intrinsics
	{
		using namespace RDX::ILOpcodes;
		using namespace RDX::Programmability;
		typedef StaticLookupTable<StaticLookupStringKey<Char, char>, NativeFunction> IntrinsicLUT;

		static IntrinsicLUT::Entry i_intrinsics[] =
		{
			//functionName										opcode		p2				p3					neverFails		isBranching		falseCheckOpcode
			{ "Core.largeint/methods/#coerce(Core.int)",	{	ILOP_isx,	sizeof(LargeInt),sizeof(Int),		true } },

			//functionName										opcode		p2				p3					neverFails		isBranching		falseCheckOpcode
			{ "Core.int/methods/__add(Core.int)",			{	ILOP_iadd,	sizeof(Int),	0,					true } },
			{ "Core.int/methods/__sub(Core.int)",			{	ILOP_isub,	sizeof(Int),	0,					true } },
			{ "Core.int/methods/__mul(Core.int)",			{	ILOP_imul,	sizeof(Int),	0,					true } },
			{ "Core.int/methods/__div(Core.int)",			{	ILOP_idiv,	sizeof(Int),	0,					false } },
			{ "Core.int/methods/__mod(Core.int)",			{	ILOP_imod,	sizeof(Int),	0,					false } },
			{ "Core.int/methods/__neg()",					{	ILOP_ineg,	sizeof(Int),	0,					true } },
			{ "Core.int/methods/#coerce(Core.largeint)",	{	ILOP_isx,	sizeof(Int),	sizeof(LargeInt),	true } },
			{ "Core.int/methods/#coerce(Core.long)",		{	ILOP_isx,	sizeof(Int),	sizeof(Long),		true } },
			{ "Core.int/methods/#coerce(Core.short)",		{	ILOP_isx,	sizeof(Int),	sizeof(Short),		true } },
			{ "Core.int/methods/#coerce(Core.double)",		{	ILOP_itof,	sizeof(Int),	sizeof(Double),		true } },
			{ "Core.int/methods/#coerce(Core.float)",		{	ILOP_itof,	sizeof(Int),	sizeof(Float),		true } },
			{ "Core.int/methods/__lt(Core.int)",			{	ILOP_ilt,	sizeof(Int),	0,					true,			true,			ILOP_ige } },
			{ "Core.int/methods/__gt(Core.int)",			{	ILOP_igt,	sizeof(Int),	0,					true,			true,			ILOP_ile } },
			{ "Core.int/methods/__le(Core.int)",			{	ILOP_ile,	sizeof(Int),	0,					true,			true,			ILOP_igt } },
			{ "Core.int/methods/__ge(Core.int)",			{	ILOP_ige,	sizeof(Int),	0,					true,			true,			ILOP_ilt } },
			{ "Core.int/methods/__eq(Core.int)",			{	ILOP_ieq,	sizeof(Int),	0,					true,			true,			ILOP_ine } },
			{ "Core.int/methods/__ne(Core.int)",			{	ILOP_ine,	sizeof(Int),	0,					true,			true,			ILOP_ieq } },

			{ "Core.largeint/methods/__add(Core.largeint)",	{	ILOP_iadd,	sizeof(LargeInt),0,					true } },
			{ "Core.largeint/methods/__sub(Core.largeint)",	{	ILOP_isub,	sizeof(LargeInt),0,					true } },
			{ "Core.largeint/methods/__mul(Core.largeint)",	{	ILOP_imul,	sizeof(LargeInt),0,					true } },
			{ "Core.largeint/methods/__div(Core.largeint)",	{	ILOP_idiv,	sizeof(LargeInt),0,					false } },
			{ "Core.largeint/methods/__mod(Core.largeint)",	{	ILOP_imod,	sizeof(LargeInt),0,					false } },
			{ "Core.largeint/methods/__neg()",				{	ILOP_ineg,	sizeof(LargeInt),0,					true } },
			{ "Core.largeint/methods/__lt(Core.largeint)",	{	ILOP_ilt,	sizeof(LargeInt),0,					true,			true,			ILOP_ige } },
			{ "Core.largeint/methods/__gt(Core.largeint)",	{	ILOP_igt,	sizeof(LargeInt),0,					true,			true,			ILOP_ile } },
			{ "Core.largeint/methods/__le(Core.largeint)",	{	ILOP_ile,	sizeof(LargeInt),0,					true,			true,			ILOP_igt } },
			{ "Core.largeint/methods/__ge(Core.largeint)",	{	ILOP_ige,	sizeof(LargeInt),0,					true,			true,			ILOP_ilt } },
			{ "Core.largeint/methods/__eq(Core.largeint)",	{	ILOP_ieq,	sizeof(LargeInt),0,					true,			true,			ILOP_ine } },
			{ "Core.largeint/methods/__ne(Core.largeint)",	{	ILOP_ine,	sizeof(LargeInt),0,					true,			true,			ILOP_ieq } },

			//functionName										opcode		p2				p3					neverFails		isBranching		falseCheckOpcode
			{ "Core.float/methods/__add(Core.float)",		{	ILOP_fadd,	sizeof(Float),	0,					true } },
			{ "Core.float/methods/__sub(Core.float)",		{	ILOP_fsub,	sizeof(Float),	0,					true } },
			{ "Core.float/methods/__mul(Core.float)",		{	ILOP_fmul,	sizeof(Float),	0,					true } },
			{ "Core.float/methods/__div(Core.float)",		{	ILOP_fdiv,	sizeof(Float),	0,					true } },
			{ "Core.float/methods/__neg()",					{	ILOP_fneg,	sizeof(Float),	0,					true } },
			{ "Core.float/methods/__lt(Core.float)",		{	ILOP_flt,	sizeof(Float),	0,					true,			true,			ILOP_fge } },
			{ "Core.float/methods/__gt(Core.float)",		{	ILOP_fgt,	sizeof(Float),	0,					true,			true,			ILOP_fle } },
			{ "Core.float/methods/__le(Core.float)",		{	ILOP_fle,	sizeof(Float),	0,					true,			true,			ILOP_fgt } },
			{ "Core.float/methods/__ge(Core.float)",		{	ILOP_fge,	sizeof(Float),	0,					true,			true,			ILOP_flt } },
			{ "Core.float/methods/__eq(Core.float)",		{	ILOP_feq,	sizeof(Float),	0,					true,			true,			ILOP_fne } },
			{ "Core.float/methods/__ne(Core.float)",		{	ILOP_fne,	sizeof(Float),	0,					true,			true,			ILOP_feq } },

			//functionName										opcode		p2				p3					neverFails		isBranching		falseCheckOpcode
			{ "Core.double/methods/__add(Core.double)",		{	ILOP_fadd,	sizeof(Double),	0,					true } },
			{ "Core.double/methods/__sub(Core.double)",		{	ILOP_fsub,	sizeof(Double),	0,					true } },
			{ "Core.double/methods/__mul(Core.double)",		{	ILOP_fmul,	sizeof(Double),	0,					true } },
			{ "Core.double/methods/__div(Core.double)",		{	ILOP_fdiv,	sizeof(Double),	0,					true } },
			{ "Core.double/methods/__neg()",				{	ILOP_fneg,	sizeof(Double),	0,					true } },
			{ "Core.double/methods/__lt(Core.double)",		{	ILOP_flt,	sizeof(Double),	0,					true,			true,			ILOP_fge } },
			{ "Core.double/methods/__gt(Core.double)",		{	ILOP_fgt,	sizeof(Double),	0,					true,			true,			ILOP_fle } },
			{ "Core.double/methods/__le(Core.double)",		{	ILOP_fle,	sizeof(Double),	0,					true,			true,			ILOP_fgt } },
			{ "Core.double/methods/__ge(Core.double)",		{	ILOP_fge,	sizeof(Double),	0,					true,			true,			ILOP_flt } },
			{ "Core.double/methods/__eq(Core.double)",		{	ILOP_feq,	sizeof(Double),	0,					true,			true,			ILOP_fne } },
			{ "Core.double/methods/__ne(Core.double)",		{	ILOP_fne,	sizeof(Double),	0,					true,			true,			ILOP_feq } },

			{ "Core.Object/methods/CanConvertTo(notnull Core.RDX.Type)",
															{	ILOP_jccp,	0,				0,					false,			true,			ILOP_jccf } },
		};
		IntrinsicLUT i_lut(i_intrinsics, sizeof(i_intrinsics)/sizeof(i_intrinsics[0]));

		const NativeFunction *LookupIntrinsicFunction(const String *str)
		{
			StaticLookupStringKey<Char, Char> strKey(str->AsChars(), str->Length());
			return i_lut.Lookup(strKey);
		}

		const NativeCallback *LookupBuiltin(const String *str)
		{
			StaticLookupStringKey<Char, Char> strKey(str->AsChars(), str->Length());
			return Builtins::bi_lut.Lookup(strKey);
		}
	}
}
